package top.lywivan.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import top.lywivan.netty.codec.ProtoStuffDecoder;
import top.lywivan.netty.codec.ProtoStuffEncoder;
import top.lywivan.netty.handler.clinet.ClientInboundHandler;
import top.lywivan.netty.handler.clinet.ClientWriterIdleHandler;

/**
 * @author :lyw.ivan
 * @date :Created in 2022/8/14
 * @description : netty客户端
 * @version: 1.0
 */
public class NettyClient {
    public static void main(String[] args) {
        NettyClient nettyClient = new NettyClient();
        nettyClient.start("127.0.0.1",8888);
    }

    private void start(String address,int port){
        //客户端只需要定义监听IO事件的Reactor
        EventLoopGroup group=new NioEventLoopGroup();
        //创建客户端的启动引导类
        Bootstrap bootstrap=new Bootstrap();
        //设置启动引导类相关参数
        bootstrap
                //设置相关Reactor，客户端只需要设置监听IO的
                .group(group)
                //设置信道的类型
                .channel(NioSocketChannel.class)
                //设置相关的handler，进行监听注册
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        //通过信道获取对于的pipeline管道
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        //设置空闲时的心跳检测消息发送
                        pipeline.addLast(new ClientWriterIdleHandler(0,5,0));
                        //设置发送消息时的一次编码
                        pipeline.addLast(new LengthFieldPrepender(4));
                        //设置发送消息时的二次编码
                        pipeline.addLast(new ProtoStuffEncoder());
                        //设置读取消息时的一次解码
                        pipeline.addLast(new LengthFieldBasedFrameDecoder(65546,0,4,0,4));
                        //设置读取消息时的二次解码
                        pipeline.addLast(new ProtoStuffDecoder());
                        //设置发送业务消息的Handler
                        pipeline.addLast(new ClientInboundHandler());
                    }
                });
        //连接服务端，并阻塞等待
        try {
            ChannelFuture future = bootstrap.connect(address, port).sync();
            //监听通道关闭事件
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //释放资源
            group.shutdownGracefully();
        }
    }
}
